//=======================================================
//  LVDS Data Output Interface 
//=======================================================
module lvds_fetch(
	// Internal Control Signals //
	 input 		          		vclk
    ,input                      reset_n
    ,input      [11 -1: 0]      weight_in  //2047>1920
    ,input      [11 -1: 0]      height_in  //2047>1080
    ,input                      lvds_vs_pulse
    ,input                      lvds_trigger
    // From lvds_input module
    ,input                      switch_req
    ,output reg                 switch_ack
    // RGB RAM Interface
    ,output reg                 back_ready
    ,input                      frmsync
    ,input      [2 -1: 0]       VS_THRESH

    ,output reg [12 -1: 0]      lvds_raddr
    ,input      [24 -1: 0]      lvds_rdata
    // Bicubic output Interface
    ,output reg                 lvds_read_valid
    ,output reg [24 -1: 0]      lvds_rdata_out
    // Display Configure Parameter
    ,input      [11 -1: 0]      SCAL_HS_PRELOGE
    ,input      [11 -1: 0]      SCAL_HS_PULSE  
    ,input      [11 -1: 0]      SCAL_HS_EPILOGE
    ,input      [11 -1: 0]      SCAL_HS_ACTIVE 
    ,input      [12 -1: 0]      SCAL_HS_TOTAL
    ,input      [11 -1: 0]      SCAL_VS_PRELOGE
    ,input      [11 -1: 0]      SCAL_VS_PULSE
    ,input      [11 -1: 0]      SCAL_VS_EPILOGE
    ,input      [11 -1: 0]      SCAL_VS_ACTIVE
    ,input      [12 -1: 0]      SCAL_VS_TOTAL
    // LVDS Fetch Data
    ,output     [8 -1: 0]       pr 
    ,output     [8 -1: 0]       pg 
    ,output     [8 -1: 0]       pb 
    ,output reg                 de
    ,output reg                 hs
    ,output reg                 vs
);

//=======================================================
//  Local parametr 
//=======================================================
localparam      RAM0_BASE = 0;
localparam      RAM1_BASE = 2048;
localparam      BIT = 8;

//=======================================================
//  REG/WIRE declarations
//=======================================================
reg                     switch_req_d;

reg     [11 -1: 0]      linePix_addr;
reg     [11 -1: 0]      linePix_count;
reg     [11 -1: 0]      line_count; //2047
reg     [12 -1: 0]      base_addr; //4095

reg     [11 -1: 0]      weight;  //2047>1920
reg     [11 -1: 0]      height;  //2047>1080

reg                     read_enable;
reg                     read_address_en;
reg                     read_enable_d1;
reg                     read_data_en;

// RGB CONTROL //
reg                     de_r;
//
reg                     start;
reg     [32 -1: 0]      pixel;
//reg     [32 -1: 0]      line_count;
reg     [32 -1: 0]      line;
reg     [32 -1: 0]      frame;

//=======================================================
//  Structural coding
//=======================================================
// register the frame height and weight at the vs_posPluse.
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    weight <= 0;
    height <= 0;
//  end else if(vs_posPluse) begin
  end else begin
    weight <= weight_in;
    height <= height_in;
  end
end

//-- generate switch_ack signal
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    switch_req_d  <= 0;
//!    switch_req_d1 <= 0;
//!    switch_req_d2 <= 0;
//!    switch_req_d3 <= 0;
  end else begin
    switch_req_d  <= switch_req;
//!    switch_req_d1 <= switch_req_d;
//!    switch_req_d2 <= switch_req_d1;
//!    switch_req_d3 <= switch_req_d2;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    switch_ack <= 0;
//!  end else if (switch_req_d2 & (!switch_req_d3)) begin
  end else if (read_enable) begin
    switch_ack <= 0;
  end else if (switch_req_d) begin
    switch_ack <= 1;
  end
end

//assign switch_pulse = switch_req_d & (!switch_req_d1);

//-- generate each frame start level
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    start <= 0;
//  end else if (lvds_vs_pulse) begin
  end else if (frmsync) begin
    start <= 1;
  end else if ((line == SCAL_VS_TOTAL-1) && (pixel == SCAL_HS_TOTAL -1))begin
    start <= 0;
  end
end

//-- counter the pix each line.
always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    pixel <= 0;
  end else if (pixel == SCAL_HS_TOTAL -1) begin
    pixel <= 0;
  end else if (start) begin
    pixel <= pixel + 1;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    line <= 0;
  end else if ((line == SCAL_VS_TOTAL-1) && (pixel == SCAL_HS_TOTAL -1))begin
    line <= 0;
  end else if (pixel == SCAL_HS_TOTAL -1) begin
    line <= line + 1;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    frame <= 0;
  end else if ((line == SCAL_VS_TOTAL-1) && (pixel == SCAL_HS_TOTAL -1))begin
    frame <= frame + 1;
  end
end

//-- vs output high
always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    vs <= 0;
  end else if (start) begin
   if ((line < (VS_THRESH + SCAL_VS_ACTIVE + SCAL_VS_PRELOGE))
               && (pixel == SCAL_HS_PRELOGE -1)) begin
     vs <= 0;
   end else if ((line >= (VS_THRESH + SCAL_VS_ACTIVE + SCAL_VS_PRELOGE)) && (line < (VS_THRESH + SCAL_VS_ACTIVE + SCAL_VS_PRELOGE + SCAL_VS_PULSE))
               && (pixel == SCAL_HS_PRELOGE -1)) begin
     vs <= 1;
   end else if ((line >= (VS_THRESH + SCAL_VS_ACTIVE + SCAL_VS_PRELOGE + SCAL_VS_PULSE)) && (line < (SCAL_VS_TOTAL))
              && (pixel == SCAL_HS_PRELOGE -1)) begin
     vs <= 0;
//!    if ((line < SCAL_VS_PULSE)
//!                && (pixel == SCAL_HS_PRELOGE -1)) begin
//!      vs <= 1;
//!    end else if (((line >= SCAL_VS_PULSE) && (line < (SCAL_VS_TOTAL)))
//!                && (pixel == SCAL_HS_PRELOGE -1)) begin
//!      vs <= 0;
    end
  end else begin
    vs <= 0; //default set low
  end
end

//-- hs output high
always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    hs <= 0;
  end else if ((pixel < SCAL_HS_PRELOGE -1) || (pixel >= (SCAL_HS_TOTAL -1)))begin
    hs <= 0;
  end else if ((pixel >= SCAL_HS_PRELOGE -1) && (pixel < (SCAL_HS_PRELOGE + SCAL_HS_PULSE -1))) begin
    hs <= 1;
  end else if ((pixel >= (SCAL_HS_PRELOGE + SCAL_HS_PULSE -1)) && (pixel < (SCAL_HS_TOTAL -1))) begin
    hs <= 0;
  end
end

//-- de output high
always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    de <= 0;
  end else if(lvds_trigger) begin
    if ((pixel < (SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE -1)) || (pixel >= (SCAL_HS_TOTAL -1))) begin
      de <= 0;
//    end else if (((line >= (SCAL_VS_PULSE + SCAL_VS_EPILOGE)) && (line < (SCAL_VS_PULSE + SCAL_VS_EPILOGE + SCAL_VS_ACTIVE ))) 
    end else if (((line >= VS_THRESH) && (line < (VS_THRESH + SCAL_VS_ACTIVE ))) 
              && (pixel >= (SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE -1)) && (pixel < (SCAL_HS_TOTAL -1)))begin
      de <= 1;
    end
  end else begin
    de <= 0;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    back_ready <= 0;
//  end else if (frmsync) begin
//    back_ready <= 0;
  end else if (((line >= VS_THRESH) && (line < (VS_THRESH + SCAL_VS_ACTIVE ))) 
            && (pixel >= (SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE -1 -1)) && (pixel < (SCAL_HS_TOTAL -1 -1)))begin
    back_ready <= 1;
  end else begin
    back_ready <= 0;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    de_r <= 0;
  end else begin
    de_r <= de;
  end
end
assign de_negPulse = (!de) & de_r;

//-- get data
//-- From the read_enable to get the lvds data back need 4 cycles.
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    read_enable <= 0;
  end else if (linePix_addr == (weight -1)) begin
    read_enable <= 0;
  end else if (((line >= (SCAL_VS_PULSE + SCAL_VS_EPILOGE)) && (line < (SCAL_VS_PULSE + SCAL_VS_EPILOGE + SCAL_VS_ACTIVE))) 
            && ((pixel >= ((SCAL_HS_PRELOGE + SCAL_HS_PULSE + SCAL_HS_EPILOGE) -1 -4)) && (pixel < (SCAL_HS_TOTAL -1 -4))))begin
    read_enable <= 1;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    read_address_en<= 0;
    read_enable_d1 <= 0;
    read_data_en   <= 0;
  end else begin
    read_address_en<= read_enable;
    read_enable_d1 <= read_address_en;
    read_data_en   <= read_enable_d1;
  end
end

//-- counter the input RGB data number
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    linePix_addr <= 0;
  end else if (linePix_addr == (weight -1)) begin
    linePix_addr <= 0;
  end else if (read_enable) begin
    linePix_addr <= linePix_addr + 1'b1;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if(!reset_n) begin
    line_count <= 0;
  end else if (line_count == (height -1) && de_negPulse) begin
    line_count <= 0;
  end else if (de_negPulse) begin
    line_count <= line_count + 1'b1;
  end
end

//-- generete the base_addr
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    base_addr <= RAM0_BASE;
  end else if (line_count[0] == 1'b0) begin
    base_addr <= RAM0_BASE;
  end else if (line_count[0] == 1'b1) begin
    base_addr <= RAM1_BASE;
  end
end

//-- generate the rgb ram interface
always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    lvds_raddr <= 0;
  end else if (read_address_en) begin
    lvds_raddr  <= (base_addr + linePix_addr);
  end else begin
    lvds_raddr <= base_addr;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    lvds_rdata_out <= 0;
    lvds_read_valid <= 0;
  end else if (read_data_en) begin
    lvds_rdata_out <= lvds_rdata;
    lvds_read_valid <= 1;
  end else begin
    lvds_rdata_out <= 0;
    lvds_read_valid <= 0;
  end
end

always@(posedge vclk or negedge reset_n)
begin
  if (!reset_n) begin
    linePix_count <= 0;
  end else if (linePix_count == (weight -1)) begin
    linePix_count <= 0;
  end else if (lvds_read_valid) begin
    linePix_count <= linePix_count + 1;
  end else begin
    linePix_count <= 0;
  end
end

//assign pr = lvds_rdata_out[3*BIT -1: BIT*2];
//assign pg = lvds_rdata_out[2*BIT -1: BIT];
//assign pb = lvds_rdata_out[1*BIT -1: 0];
assign pr = lvds_rdata[3*BIT -1: BIT*2];
assign pg = lvds_rdata[2*BIT -1: BIT];
assign pb = lvds_rdata[1*BIT -1: 0];

endmodule

